package com.aegis.core.manager;

import com.aegis.core.constants.AegisTokenRedisConstants;
import com.aegis.core.model.AegisAppInfo;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;

/**
 * @Author wuweixin
 * 
 * @Version 1.0
 * @Descritube
 */
public class AegisAppManager {

    private static final Object SAVE_LOCK = new Object();

    private static String appId;

    private AegisAppManager() {
        throw new UnsupportedOperationException("AegisAppManager is a utility class and cannot be instantiated");
    }

    public static void register(String appId) {
        if (AegisAppManager.appId != null) {
            throw new ExceptionInInitializerError("禁止重复注册应用");
        }
        checkAppExisting(appId);
        AegisAppManager.appId = appId;
    }

    public static String getAppId() {
        return appId;
    }

    /**
     * 更新或添加应用信息
     *
     * @param appInfo 应用信息实体（appId必须非空）
     */
    public static void saveOrUpdateAppInfo(AegisAppInfo appInfo) {
        validateAppInfo(appInfo);
        saveOrUpdateAppInfoMap(map -> map.put(appInfo.getAppId(), appInfo));
    }

    /**
     * 删除应用
     * @param appId
     */
    public static void removeApp(String appId) {
        saveOrUpdateAppInfoMap(map -> {
            map.remove(appId);
        });
    }

    /**
     * 批量添加应用信息（自动去重）
     *
     * @param appInfos 应用信息列表
     */
    public static void addAppInfos(List<AegisAppInfo> appInfos) {
        Objects.requireNonNull(appInfos, "应用信息列表不能为空");
        saveOrUpdateAppInfoMap(map -> {
            for (AegisAppInfo info : appInfos) {
                validateAppInfo(info);
                map.put(info.getAppId(), info);
            }
        });
    }

    /**
     * 获取所有应用信息的列表
     *
     * @return 可修改的应用信息列表（修改不会影响存储数据）
     */
    public static List<AegisAppInfo> getAppInfos() {
        return new ArrayList<>(getAppInfoMap().values());
    }


    /**
     * 获得某个应用的信息
     *
     * @param appId
     * @return
     */
    public static AegisAppInfo getAppInfo(String appId) {
        return getAppInfoMap().get(appId);
    }

    /**
     * 获取应用信息Map
     *
     * @return 线程安全的Map视图（直接修改会影响存储数据）
     */
    public static Map<String, AegisAppInfo> getAppInfoMap() {
        Map<String, AegisAppInfo> map = (Map<String, AegisAppInfo>)
                AegisComponentManager.getAegisDao().getObject(AegisTokenRedisConstants.APP_INFO_KEY);
        return map != null ? new ConcurrentHashMap<>(map) : new ConcurrentHashMap<>();
    }

    /**
     * @param appId
     * @return
     */
    public static boolean containApp(String appId) {
        Map<String, AegisAppInfo> appInfoMap = getAppInfoMap();
        return appInfoMap.containsKey(appId);
    }

    /**
     * 检查APP是否存在，不存在直接抛异常
     *
     * @param appId
     */
    public static void checkAppExisting(String appId) {
        if (!containApp(appId)) {
            throw new IllegalArgumentException("不存在的应用id");
        }
    }

    /**
     * @param appInfo
     */
    private static void validateAppInfo(AegisAppInfo appInfo) {
        Objects.requireNonNull(appInfo, "应用信息不能为空");
        Objects.requireNonNull(appInfo.getAppId(), "appId不能为空");
    }

    /**
     * @param updateLogic 回调返回一个当前应用信息的map，按需求操作map，如添加应用信息，读取应用信息等
     */
    private static void saveOrUpdateAppInfoMap(Consumer<Map<String, AegisAppInfo>> updateLogic) {
        synchronized (SAVE_LOCK) {
            Map<String, AegisAppInfo> newMap = new ConcurrentHashMap<>(getAppInfoMap());
            updateLogic.accept(newMap);
            AegisComponentManager.getAegisDao().setObject(AegisTokenRedisConstants.APP_INFO_KEY, newMap, -1);
        }
    }


}
